package pro.cherish.knowledgeruntime.spring;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.springframework.util.ClassUtils;

import java.util.Map;

/**
 * @author 创建人：cherish
 * @version 版本号：V1.0
 * <p>
 * ***************************修订记录************************************
 * 2019-11-03 cherish 创建该类功能。
 * **********************************************************************
 * </p>
 * @ClassName 类名：SpringContextUtil
 * @Description 功能说明：
 * <p>
 * TODO
 * </p>
 * **********************************************************************
 * @date 创建日期： 2019-11-03 cherish
 */
@Slf4j
public class SpringContextUtil {

    private static final String SPRING_APPLICATION_CONTEXT_AWARE_CLASS="pro.cherish.knowledgeruntime.spring.RuntimeApplicationContext";


    private static Class getSpringApplicationContextAwareClass()throws Exception{
        return ClassUtils.forName(SPRING_APPLICATION_CONTEXT_AWARE_CLASS, Thread.currentThread().getContextClassLoader());
    }

    /**
     * 获取Spring Bean
     * @param beanName bean名称
     * @return
     */
    public static <E> E getBean(String beanName){
        try{
            Class applicationContextAwareClass=getSpringApplicationContextAwareClass();
            Object result= MethodUtils.invokeStaticMethod(applicationContextAwareClass,"getBean", new Object[]{beanName});
            return (E)result;
        }catch(Exception e){
            log.error("Error get spring applicationContext bean {}",beanName,e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取Spirng Bean
     * @param type 类类型
     * @param <E>
     * @return
     */
    public static <E> E getBeanByType(Class<? extends E> type) {
        try{
            Class applicationContextAwareClass=getSpringApplicationContextAwareClass();
            Object result=MethodUtils.invokeStaticMethod(applicationContextAwareClass,"getBeanByType", new Object[]{type});
            return (E)result;
        }catch(Exception e){
            log.error("Error get spring applicationContext bean of type {}",type.getClass(),e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取Spring Bean
     * @param type 类类型
     * @param <T>
     * @return
     */
    public static <T> Map<String, T> getBeansOfType(Class<T> type){
        try{
            Class applicationContextAwareClass=getSpringApplicationContextAwareClass();
            Object result=MethodUtils.invokeStaticMethod(applicationContextAwareClass,"getBeansOfType", new Object[]{type});
            return (Map<String, T>)result;
        }catch(Exception e){
            log.error("Error get spring applicationContext bean of type {}",type.getClass(),e);
            throw new RuntimeException(e);
        }
    }

    public static void initAutowireFields(Object instance){
        try{
            Class applicationContextAwareClass=getSpringApplicationContextAwareClass();
            MethodUtils.invokeStaticMethod(applicationContextAwareClass,"initAutowireFields", new Object[]{instance});
        }catch(Exception e){
            log.error("Error get spring applicationContext initAutowireFields {}",instance.getClass(),e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据注解获取Bean
     * @param type
     * @return
     */
    public static Map<String,Object> getBeansWithAnnotation(Class type){
        try{
            Class applicationContextAwareClass=getSpringApplicationContextAwareClass();
            Object result=MethodUtils.invokeStaticMethod(applicationContextAwareClass,"getBeansWithAnnotation", new Object[]{type});
            return (Map<String, Object>)result;
        }catch(Exception e){
            log.error("Error get spring applicationContext bean with annotation {}",type.getClass(),e);
            throw new RuntimeException(e);
        }
    }
}

